﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Compilex.BaseLibrary;
using Infraestruturex.Automata.SPA;
using Infraestruturex.Automata;

namespace Compilex
{
    [Serializable]
    public class SyntaticAnalyzer
    {
        public ITokenProvider TokenProvider { get; set; }
        public SemanticActionManager SemanticActionManager { get; set; }
        public string LanguageName { get; set; }

        public SimpleHashtable<string, SPA> Submachines { get; set; }
        public SPA StartSubmachine { get; set; }

        public string LastError { get; private set; }

        public SyntaticAnalyzer()
        {
        }

        public SyntaticAnalyzer(SPA startSubmachine, SimpleHashtable<string, SPA> submachines)
        {
            this.StartSubmachine = startSubmachine;
            this.Submachines = submachines;
        }

        

        public void Analyze()
        {
            if (!TryAnalyze(false))
                throw new SyntaticException(LastError);
        }

        public bool TryAnalyze()
        {
            return TryAnalyze(true);
        }

        private bool TryAnalyze(bool catchExceptions)
        {
            try
            {
                if (TokenProvider == null)
                    throw new InvalidOperationException("Um TokenProvider deve ser definido antes da analise");

                StartSubmachine.TokenProvider = TokenProvider;
                bool ok = StartSubmachine.Accepts();
                if (!ok)
                {
                    LastError = "Erro de sintaxe ao ler token \"" +
                        TokenProvider.PeekNextTokenLexeme() + "\" (linha "+ TokenProvider.CurrentLine + ")";

                }
                return ok;
            }
            catch (SyntaticException e)
            {
                if (catchExceptions)
                {
                    LastError = e.Message + " (linha "+ TokenProvider.CurrentLine + ")";
                    return false;
                }
                else
                    throw;
            }
        }  
    }
}
